home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue68 / System / DeskManager.dpr < prev    next >
Encoding:
Text File  |  2001-03-06  |  8.6 KB  |  255 lines

  1. library DeskManager;
  2.  
  3. {---------------------------------------------------------------------
  4.     Name:       DeskManager
  5.     Purpose:    Provide direct access to the desktop list-view control
  6.                 Written by Dave Jewell, 2001 for the Delphi Magazine
  7.                 Based on an original idea by Jeffrey Richter.
  8. -----------------------------------------------------------------------}
  9.  
  10. uses
  11.   Windows, Messages, CommCtrl, DeskManMessages;
  12.  
  13. {$R DeskManagerDlg.res}
  14.  
  15. var
  16.     Hook: HHook = 0;            // used for message chaining
  17.     AppWindow: hWnd = 0;    // handle of application window
  18.     DeskLV: hWnd = 0;           // desktop list-view handle
  19.  
  20. //------------------------------------------------------------------------------
  21. // Get a window to the ListView control which implements the desktop
  22. //------------------------------------------------------------------------------
  23.  
  24. function DeskManagerListView: HWnd; stdcall; export;
  25. var
  26.     buff: array [0..255] of Char;
  27. begin
  28.     if DeskLV = 0 then begin
  29.         DeskLV := GetWindow (GetWindow (FindWindow ('ProgMan', Nil), gw_Child), gw_Child);
  30.         if DeskLV <> 0 then begin
  31.             GetClassName (DeskLV, buff, sizeof (buff));
  32.             if buff <> 'SysListView32' then DeskLV := 0;
  33.         end;
  34.  
  35.         if DeskLV = 0 then MessageBox (0, 'Panic: Desktop ListView control not found', 'DeskManager', mb_OK);
  36.     end;
  37.  
  38.     Result := DeskLV;
  39. end;
  40.  
  41. //------------------------------------------------------------------------------
  42. // Get the thread ID of the Explorer thread which manages the desktop
  43. //------------------------------------------------------------------------------
  44.  
  45. function DeskManagerShellThread: DWord; stdcall; export;
  46. begin
  47.     Result := GetWindowThreadProcessID (DeskManagerListView, Nil);
  48. end;
  49.  
  50. //------------------------------------------------------------------------------
  51. // Redraw all desktop items after changing some metric
  52. //------------------------------------------------------------------------------
  53.  
  54. procedure RedrawItems;
  55. var
  56.     Count: Integer;
  57. begin
  58.     Count := SendMessage (DeskManagerListView, lvm_GetItemCount, 0, 0);
  59.     SendMessage (DeskManagerListView, lvm_RedrawItems, 0, Count - 1);
  60.     UpdateWindow (DeskManagerListView);
  61. end;
  62.  
  63. function HandleGetItemText (DlgWnd: hWnd; Index: Integer): Integer;
  64. var
  65.     Count: Integer;
  66.     cds: TCopyDataStruct;
  67.     buff: array [0..255] of Char;
  68. begin
  69.     Result := 0;
  70.     Count := SendMessage (DeskManagerListView, lvm_GetItemCount, 0, 0);
  71.     if (Index >= 0) and (Index < Count) then begin
  72.         buff[0] := #0;
  73.         ListView_GetItemText (DeskManagerListView, Index, 0, buff, sizeof (buff));
  74.         cds.dwData := DM_GetItemText;
  75.         cds.cbData := lstrlen (buff) + 1;
  76.         cds.lpData := @buff;
  77.         Result := SendMessage (AppWindow, wm_CopyData, DlgWnd, Integer (@cds));
  78.     end;
  79. end;
  80.  
  81. //------------------------------------------------------------------------------
  82. // This is the window proc of the hidden desk manager dialog.
  83. // Runs in Explorer's process context.
  84. //------------------------------------------------------------------------------
  85.  
  86. function DeskManDlgProc (DlgWnd: hWnd; Msg, wParam, lParam: Integer): Integer; stdcall;
  87. begin
  88.     Result := 0;
  89.  
  90.     case Msg of
  91.  
  92.     // -------- Get number of items on the desktop
  93.  
  94.     DM_GetItemCount:
  95.         Result := ListView_GetItemCount (DeskManagerListView);
  96.  
  97.     // -------- Get desktop text colour
  98.  
  99.     DM_GetTextColor:
  100.         Result := SendMessage (DeskManagerListView, LVM_GetTextColor, 0, 0);
  101.  
  102.         // -------- Set desktop text colour: lParam = new color
  103.  
  104.         DM_SetTextColor:
  105.             begin
  106.             Result := SendMessage (DeskManagerListView, lvm_SetTextColor, 0, lParam);
  107.                RedrawItems;
  108.         end;
  109.  
  110.         // -------- Get text of a designated item: wParam = index
  111.  
  112.         DM_GetItemText:
  113.             Result := HandleGetItemText (DlgWnd, wParam);
  114.  
  115.         // -------- Destroy the dialog window
  116.  
  117.         wm_Close:
  118.             DestroyWindow (DlgWnd);
  119.     end;
  120. end;
  121.  
  122. //------------------------------------------------------------------------------
  123. // Implement the message hook.  Runs in Explorer's process context
  124. //------------------------------------------------------------------------------
  125.     
  126. function GetMsgProc (nCode: Integer; wParam: wParam; lParam: lParam): lParam; stdcall;
  127. begin
  128.     if Hook = 0 then begin
  129.         Hook := (PMsg (lParam))^.lParam;
  130.         // Create the server window to service client requests
  131.         CreateDialog (hInstance, PChar (101), 0, @DeskManDlgProc);
  132.     // Get application window handle
  133.     AppWindow := (PMsg (lParam))^.wParam;
  134.         // Tell the original application that server is ready
  135.         PostThreadMessage (GetWindowThreadProcessID (AppWindow, Nil), wm_Null, 0, 0);
  136.     end;
  137.  
  138.     Result := CallNextHookEx (Hook, nCode, wParam, lParam);
  139. end;
  140.  
  141. //------------------------------------------------------------------------------
  142. // Initialise and inject the DLL.  Runs in the client application context
  143. //------------------------------------------------------------------------------
  144.  
  145. function DeskManagerLoad (AppWindow: hWnd): Bool; stdcall; export;
  146. begin
  147.     Result := False;
  148.     // Various safety checks...
  149.     if (Hook = 0) and (FindWindow (Nil, 'Delphi Desktop 2001') = 0) then begin
  150.         // Hook the desktop thread
  151.         Hook := SetWindowsHookEx (wh_GetMessage, @GetMsgProc, hInstance, DeskManagerShellThread);
  152.         Result := Hook <> 0;
  153.         // If success, post a message to force DLL injection
  154.         if Result then Result := PostThreadMessage (DeskManagerShellThread, wm_Null, AppWindow, Hook);
  155.     end;
  156. end;
  157.  
  158. function DeskManagerUnload: Bool; stdcall; export;
  159. begin
  160.     if Hook <> 0 then Result := UnhookWindowsHookEx (Hook) else Result := False;
  161.     Hook := 0;
  162. end;
  163.  
  164.  
  165. exports
  166.     DeskManagerLoad,
  167.     DeskManagerUnload,
  168.     DeskManagerListView,
  169.     DeskManagerShellThread;
  170.  
  171. begin
  172. end.
  173.  
  174. #include "CmnHdr.H"
  175. #include <Windows.H>
  176. #include <WindowsX.H>
  177. #include <CommCtrl.H>
  178. #include "Resource.H"
  179.  
  180. static const TCHAR g_szRegSubKey[] = __TEXT ("Software\\Richter\\Desktop Item Position Saver");
  181.  
  182. void SaveListViewItemPositions(HWND hwndLV)
  183. {
  184.    int nItem, nMaxItems = ListView_GetItemCount(hwndLV);
  185.    HKEY hkey;
  186.    DWORD dwDisposition;
  187.  
  188.    // When saving new positions, delete the old position
  189.    // information that is currently in the registry.
  190.    RegDeleteKey (HKEY_CURRENT_USER, g_szRegSubKey);
  191.  
  192.    // Create the registry key to hold the info
  193.    RegCreateKeyEx (HKEY_CURRENT_USER, g_szRegSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkey, &dwDisposition);
  194.  
  195.    for (nItem = 0; nItem < nMaxItems; nItem++) 
  196.    {
  197.       TCHAR szName[_MAX_PATH];
  198.       POINT pt;
  199.  
  200.       // Get the name and position of a listview item.
  201.       ListView_GetItemText (hwndLV, nItem, 0, szName, _MAX_PATH);
  202.       ListView_GetItemPosition (hwndLV, nItem, &pt);
  203.  
  204.       // Save the name and position in the registry.
  205.       RegSetValueEx (hkey, szName, 0, REG_BINARY, (PBYTE) &pt, sizeof(pt));
  206.    }
  207.  
  208.    RegCloseKey(hkey);
  209. }
  210.  
  211. //--------------------------------------------------------------------------
  212.  
  213. void RestoreListViewItemPositions (HWND hwndLV) 
  214. {
  215.    HKEY hkey;
  216.    LONG l = RegOpenKeyEx(HKEY_CURRENT_USER, g_szRegSubKey, 0, KEY_QUERY_VALUE, &hkey);
  217.    if (l == ERROR_SUCCESS) {
  218.       int nIndex;
  219.  
  220.       // If the listview has AutoArrange on, temporarily turn it off.
  221.       DWORD dwStyle = GetWindowStyle (hwndLV);
  222.       if (dwStyle & LVS_AUTOARRANGE) SetWindowLong (hwndLV, GWL_STYLE, dwStyle & ~LVS_AUTOARRANGE);
  223.  
  224.       l = NO_ERROR;
  225.       for (nIndex = 0; l != ERROR_NO_MORE_ITEMS; nIndex++) {
  226.          TCHAR szName[_MAX_PATH];
  227.          POINT pt;
  228.          LV_FINDINFO lvfi;
  229.          int cbValueName = _MAX_PATH;
  230.          int cbData = sizeof(pt), nItem;
  231.          DWORD dwType;
  232.  
  233.          // Read a value name and position from the registry.
  234.          l = RegEnumValue(hkey, nIndex, szName, &cbValueName, 
  235.             NULL, &dwType, (PBYTE) &pt, &cbData);
  236.  
  237.          if (l == ERROR_NO_MORE_ITEMS) continue;
  238.  
  239.          if ((dwType == REG_BINARY) && (cbData == sizeof(pt))) {
  240.             // The value is something that we recognize; try to find
  241.             // an item in the listview control that matches the name.
  242.             lvfi.flags = LVFI_STRING; 
  243.             lvfi.psz = szName;
  244.             nItem = ListView_FindItem(hwndLV, -1, &lvfi);
  245.             if (nItem != -1) ListView_SetItemPosition(hwndLV, nItem, pt.x, pt.y);    
  246.          }
  247.       }
  248.       // Turn AutoArrange back on if it was originally on.
  249.       SetWindowLong(hwndLV, GWL_STYLE, dwStyle);
  250.       RegCloseKey(hkey);
  251.    }
  252. }
  253.  
  254.  
  255.